/*
 * Copyright (c) 2011-2014, fortiss GmbH.
 * Licensed under the Apache License, Version 2.0.
 *
 * Use, modification and distribution are subject to the terms specified
 * in the accompanying license file LICENSE.txt located at the root directory
 * of this software distribution. A copy is available at
 * http://chromosome.fortiss.org/.
 *
 * This file is part of CHROMOSOME.
 *
 * $Id: componentRepository_buildComponentInstance.c 7548 2014-02-20 16:16:37Z geisinger $
 */

/**
 * \file componentRepository_buildComponentInstance.c
 */

/*
 * This example shows how to properly build a new component instance
 * by using the component repository and how to plug this new component
 * into the system.
 *
 * We assume here that the system is properly configured (e.g. the respective
 * component manifests are registered etc.).
 * Usually XMT will do this for you.
 */

/******************************************************************************/
/***   Includes                                                             ***/
/******************************************************************************/
#include "xme/core/nodeManager/include/componentRepositoryBuilder.h"
#include "xme/core/plugAndPlay/include/plugAndPlayClient.h"
#include "xme/core/plugAndPlay/include/plugAndPlayManager.h"

/******************************************************************************/
/***   Variables                                                            ***/
/******************************************************************************/
static const xme_core_componentType_t myComponentType = (xme_core_componentType_t) 5000; ///< The component type identifier is usually generated by XMT.

static const uint16_t myComponentTypePort = 0u; ///< The port type identifier is usually generated by XMT.

/******************************************************************************/
/***   Prototypes                                                           ***/
/******************************************************************************/
/**
 * \brief Here we create a new component on the local node and plug it in
 *        via the plug and play client.
 *        You can call the following code from one of your component's
 *        *_step() functions. Just replace myComponentType and myComponentTypePort
 *        with actual values from your application's component types.
 */
void
plugInOnPnpClient(void);

/**
 * \brief Here we create a new component on a another node and plug it in
 *        via the plug and play manager.
 *
 *        You can call the following code from one of your component's
 *        *_step() functions. Just replace myComponentType and myComponentTypePort
 *        with actual values from your application's component types.
 */
void
plugInOnPnpManager(void);

/******************************************************************************/
/***   Implementation                                                       ***/
/******************************************************************************/
void
plugInOnPnpClient(void)
{
    xme_status_t status = XME_STATUS_INTERNAL_ERROR;
    xme_core_nodeMgr_compRep_componentBuilder_t* builder = NULL;
    xme_core_nodeMgr_compRep_componentHandle_t componentHandle = XME_CORE_NODEMGR_COMPREP_INVALID_HANDLE;

    // Create a new builder
    builder = xme_core_nodeMgr_compRep_createBuilder
    (
        XME_CORE_NODE_LOCAL_NODE_ID,
        myComponentType
    );
    // This will initialize a new component instance with default settings
    // as defined in its manifest

    if (NULL == builder) { return; }

    // If you want to set some component instance-specific settings,
    // use the xme_core_nodeMgr_compRep_builderSet* functions.
    xme_core_nodeMgr_compRep_builderSetInitializationString(builder, "customComponentInitString");
    xme_core_nodeMgr_compRep_builderSetQueueSize(builder, myComponentTypePort, 2u);
    
    // Now we finalize the new component ...
    status = xme_core_nodeMgr_compRep_build(builder, &componentHandle);
    if (XME_STATUS_SUCCESS == status) { return; }

    // The component will have the following state: (you don't need to check this)
    XME_ASSERT_NORVAL(XME_CORE_NODEMGR_COMPREP_STATE_PREPARED == xme_core_nodeMgr_compRep_getState(componentHandle));

    // ... and trigger the plug-in
    status = xme_core_pnp_pnpClient_plugInNewComponent(componentHandle);
    if (XME_STATUS_SUCCESS == status) { return; }

    // The component will have the following state: (you don't need to check this)
    XME_ASSERT_NORVAL(XME_CORE_NODEMGR_COMPREP_STATE_ANNOUNCED == xme_core_nodeMgr_compRep_getState(componentHandle));

    // The plug and play client will now announce the component to the plug and play manager
    // which will compute a new configuration of the CHROMOSOME network and update all affected
    // nodes.
    // If our new component has a communication partner it will be plugged-in and
    // its state will switch to XME_CORE_NODEMGR_COMPREP_STATE_CREATED and it will start
    // execution.
}

void
plugInOnPnpManager(void)
{
    xme_status_t status = XME_STATUS_INTERNAL_ERROR;
    xme_core_nodeMgr_compRep_componentBuilder_t* builder = NULL;
    xme_core_nodeMgr_compRep_componentHandle_t componentHandle = XME_CORE_NODEMGR_COMPREP_INVALID_HANDLE;

    // Now we choose another node than the local one.
    // To get a list of all registered nodes, refer to the xme_core_directory_nodeRegistryController
    // component.
    builder = xme_core_nodeMgr_compRep_createBuilder
    (
        (xme_core_node_nodeId_t)2,
        myComponentType
    );
    if (NULL == builder) { return; }

    xme_core_nodeMgr_compRep_builderSetInitializationString(builder, "customComponentInitString");
    xme_core_nodeMgr_compRep_builderSetQueueSize(builder, myComponentTypePort, 2u);
    
    status = xme_core_nodeMgr_compRep_build(builder, &componentHandle);
    if (XME_STATUS_SUCCESS == status) { return; }

    // The component will have the following state: (you don't need to check this in your code)
    XME_ASSERT_NORVAL(XME_CORE_NODEMGR_COMPREP_STATE_PREPARED == xme_core_nodeMgr_compRep_getState(componentHandle));

    // Components on another node than the local one, can only be plugged in via the plug and play
    // manager
    status = xme_core_pnp_pnpManager_plugInNewComponent(componentHandle);
    if (XME_STATUS_SUCCESS == status) { return; }

    // The component will have the following state: (you don't need to check this in your code)
    XME_ASSERT_NORVAL(XME_CORE_NODEMGR_COMPREP_STATE_ANNOUNCED == xme_core_nodeMgr_compRep_getState(componentHandle));

    // The same steps will happen now, as if the plug and play manager would have received
    // the request from the selected node.
}

int
main(int argc, char **argv)
{
    XME_UNUSED_PARAMETER(argc);
    XME_UNUSED_PARAMETER(argv);

    plugInOnPnpClient();
    plugInOnPnpManager();

    return 0;
}
